package com.lyh.miniostudy.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.lyh.miniostudy.config.MinioConfig;
import com.lyh.miniostudy.service.MinioService;
import io.minio.BucketExistsArgs;
import io.minio.GetObjectArgs;
import io.minio.GetObjectResponse;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.StatObjectArgs;
import io.minio.StatObjectResponse;
import io.minio.errors.ErrorResponseException;
import io.minio.errors.InsufficientDataException;
import io.minio.errors.InternalException;
import io.minio.errors.InvalidResponseException;
import io.minio.errors.MinioException;
import io.minio.errors.ServerException;
import io.minio.errors.XmlParserException;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;

/**
 * @describe
 * @author liang_yh
 * @since 2024/12/18
 */
@Service
@Slf4j
public class MinioServiceImpl implements MinioService {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioConfig minioConfig;

    @Override
    public String upload(MultipartFile file) throws Exception {

        String originalFilename = file.getOriginalFilename();

        if (StrUtil.isBlank(originalFilename)) {
            throw new RuntimeException();
        }
        // 重新命名文件，文件名为 uuid 生成
        String fileName = IdUtil.getSnowflakeNextIdStr() + originalFilename.substring(originalFilename.lastIndexOf("."));
        // 设置存储目录，设置 年-月和日两级目录
        String objectName = DateUtil.format(new Date(), "yyyy-MM/dd") + "/" + fileName;
        try {
            PutObjectArgs objectArgs = PutObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(objectName)
                    .stream(file.getInputStream(), file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build();
            // 文件名称相同会覆盖
            minioClient.putObject(objectArgs);
        } catch (Exception e) {
            // 异常处理
            log.warn(e.getMessage());
            return null;
        }
        // 拼接minio的端点和存储桶的名称
        return getPrefix() + objectName;

    }

    public String getPrefix() {
        return minioConfig.getEndpoint() + "/" + minioConfig.getBucketName() + "/";
    }


    @Override
    public void download(HttpServletResponse response, String file) {
        // 获取文件的名称
        String fileName = removeMinioEndpoint(file);
        try {
            boolean fileExists = fileExists(fileName);
            if (!fileExists) {
                throw new RuntimeException("文件不存在");
            }

            InputStream fileIo = minioClient.getObject(
                    GetObjectArgs.builder()
                            .bucket(minioConfig.getBucketName())
                            .object(fileName)
                            .build());

            // 设置响应类型
            response.setContentType("application/octet-stream");
            // 设置附件名称
            response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
            IOUtils.copy(fileIo, response.getOutputStream());
            response.flushBuffer();

        } catch (Exception e) {
            // 异常处理
            e.printStackTrace();
        }
    }

    @Override
    public void delete(String file) {

    }


    /**
     * 移除文件路径的前缀，获取文件的名称
     *
     * @param file 文件路径
     */
    public String removeMinioEndpoint(String file) {
        return file.substring(getPrefix().length() - 1);
    }


    /**
     * 根据文件名称删除文件
     *
     * @param file 文件路径
     */
    public void deleteFile(String file) {
        // 获取文件的名称
        String fileName = removeMinioEndpoint(file);
        try {
            minioClient.removeObject(
                    RemoveObjectArgs.builder()
                            .bucket(minioConfig.getBucketName())
                            .object(fileName)
                            .build());
        } catch (Exception e) {
            // 异常处理
            e.printStackTrace();
        }
    }



    @Override
    public boolean fileExists(String fileName) throws Exception {
            try {
                // 使用 statObject 方法检查对象是否存在
                minioClient.statObject(
                        StatObjectArgs.builder()
                                .bucket(minioConfig.getBucketName())
                                .object(fileName)
                                .build()
                );
                return true; // 对象存在
            } catch (MinioException e) {
                // 如果对象不存在或发生其他 MinIO 错误，返回 false
                e.printStackTrace();
                return false;
            } catch (Exception e) {
                // 处理其他异常
                e.printStackTrace();
                return false;
            }
    }


    /**
     *  判断Bucket是否存在，true：存在，false：不存在
     * @return
     * @throws Exception
     */
    @Override
    public boolean bucketExists(String bucketName) throws Exception {
        return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
    }

}

